#ifndef __OS_CARD_H__
#define __OS_CARD_H__

/* os_cards.h:
 * card structure 
 *
 * (C) Copyright 2013 Ramone de Castillon 
 * ramone.castillon@gmail.com
 * http://poker-botting.blogspot.fr/.
 *
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the GNU Lesser General Public License
 * (LGPL) version 2.1 which accompanies this distribution, and is available at
 * http://www.gnu.org/licenses/lgpl-2.1.html
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
 * Lesser General Public License for more details.
 *
 */

#include "os_defs.h"

#define OS_CARD_DIAMON 0
#define OS_CARD_HEART 1
#define OS_CARD_SPIKE 2
#define OS_CARD_CLUB 3

#define OS_CARD_2 0
#define OS_CARD_TEN 8
#define OS_CARD_JACK 9
#define OS_CARD_QUEEN 10
#define OS_CARD_KING 11
#define OS_CARD_AS 12

static inline char cardval_tostr(uint8_t cv)
{
	switch(cv) {
		case OS_CARD_TEN:
			return 'T';
		case OS_CARD_JACK:
			return 'J';
		case OS_CARD_QUEEN:
			return 'Q';
		case OS_CARD_KING:
			return 'K';
		case OS_CARD_AS:
			return 'A';
		default:
			if (cv <=7)
				return '2' + cv;
			else
				return 'E';
	};
}

static inline char cardcol_tostr(uint8_t cc)
{
	switch(cc) {
		case OS_CARD_DIAMON:
			return 'd';
		case OS_CARD_HEART:
			return 'h';
		case OS_CARD_SPIKE:
			return 's';
		case OS_CARD_CLUB:
			return 'c';
		default:
			return 'e';
	};	
}

static inline uint8_t os_cardcode_to_color(uint8_t code)
{
	return code/13;
}

static inline uint8_t os_cardcode_to_value(uint8_t code)
{
	return code%13;
}

#define CARD_STR_SIZE 3
static inline const char *os_cardcode_tostr(uint8_t code, char str[CARD_STR_SIZE])
{
	uint8_t cc = os_cardcode_to_color(code);
	uint8_t cv = os_cardcode_to_value(code);

	if (code == OS_CARD_NONE) {
		strncpy(str, "XX", CARD_STR_SIZE);
		return str;
	}

	snprintf(str, CARD_STR_SIZE, "%c%c", 
		cardval_tostr(cv),
		cardcol_tostr(cc));
	return str;
}

static inline uint8_t os_cardstr_tocode(const char *str)
{
	uint8_t ct;
	uint8_t cv;
	
	if (!str || str[0]=='\0' || str[1] == '\0' || str[2] != '\0') {
		return OS_CARD_NONE;
	}
	
	/* card type: hearts, clubs, diamonds and spades */
	switch(str[1]) {
		case 'd':
			ct=OS_CARD_DIAMON;
			break;
		case 'h':
			ct=OS_CARD_HEART;
			break;
		case 's':
			ct=OS_CARD_SPIKE;
			break;
		case 'c':
			ct=OS_CARD_CLUB;
			break;
		default:
			printf("cdt err %c\n", str[1]);
			assert(0);
			return OS_CARD_NONE;
	};


	switch(str[0]) {
		case 'T':
		case 't':
			cv=OS_CARD_TEN;
			break;
		case 'J':
		case 'j':
			cv=OS_CARD_JACK;
			break;
		case 'Q':
		case 'q':
			cv=OS_CARD_QUEEN;
			break;
		case 'K':
		case 'k':
			cv=OS_CARD_KING;
			break;	
		case 'A':
		case 'a':
		case '1':
			cv=OS_CARD_AS;
			break;
		default:
			if (str[0] >= '2' && str[0] <= '9')
				cv = str[0] - '2';
			else {
				printf("cv err %c\n", str[0]);
				assert(0);
				return OS_CARD_NONE;
			}
	}
	
	return  cv + ct*13;
}

static inline int os_is_bad_card(uint8_t card)
{
	if (card > 13+3*13 || card == OS_CARD_NONE)
		return 1;
	return 0;
}

static inline void convert_ccode_to_cards(uint32_t ccode, char cards[2])
{
	int suited = (ccode%2);
	if (suited) ccode--;
	ccode/=2;
	cards[0]=ccode%13;
	cards[1]=ccode/13;
}

/* get a random (but unused) card. don't take into account the way the user is playing */
static inline uint8_t set_randomcard(uint8_t randCards[OS_NB_CARDS])
{
	uint8_t c;

random_num:
	/* warning: we cannot get reliable random number with
	 * rand()%52 because 52 is not a power of 2 !! */
#define OS_NB_CARDS_POW2 52

	c = rand()%OS_NB_CARDS_POW2;
	if (c >= OS_NB_CARDS) {
		/* such cards doesn't exist: try again */
		goto random_num;
	}
	
	/* ok, from now we got a correct number, but we have
	   to check if this card is not already used. 
	   if randCards[c] = PE_CARDS_NONE, then that mean 
	   we already pick up this card. so we will try an another cards */
	if (randCards[c]!=OS_CARD_NONE)
		goto random_num;

	/* success ! we have the card we want.*/ 
	randCards[c]=c;
	assert(c < OS_NB_CARDS && c!= OS_CARD_NONE);

	return c;
}

static inline void set_cards(uint8_t cards[OS_NB_CARDS], uint8_t value)
{
	assert(value < OS_NB_CARDS);
	//assert(cards[value] == OS_CARD_NONE);
	cards[value]=value;
}

static inline int is_hand_pair(uint8_t cards[2])
{
	return (cards[0]%13 == cards[1]%13);
}


#endif /*  __OS_CARD_H__ */
